#include "NBuffer.h"

/**
 * @brief 清空缓冲区。
 *
 * @param obj 本对象
 */
static void
n_buffer_clean (NBuffer* obj)
{
        if (!obj)
                return;
        for (int i = 0; i < 12; ++i)
                obj->numbuf[i] = 0x0;
        for (int i = 0; i < 4; ++i)
                obj->scibuf[i] = 0x0;
        obj->dotpot = 0x0;
}

void
n_buffer_init (NBuffer* obj)
{
        number_init (NUMBER (obj));
        object_set_destory_func (obj, n_buffer_destory);
        n_buffer_clean (obj);
}

void
n_buffer_destruction (NBuffer* obj)
{
        number_destruction (NUMBER (obj));
}

OBJECT_DEFINE_START (NBuffer, n_buffer)

/**
 * @brief 格式化整数到数字缓冲区。
 *
 * @param obj 本对象
 * @param num 整数
 */
static void
n_buffer_format_with_integer (NBuffer* obj, int_max num)
{
        int_max posi_num, tmp;
        bool    is_positive;

        if (num < 0) {
                posi_num    = -num;
                is_positive = false;
        } else {
                posi_num    = num;
                is_positive = true;
        }

        for (int i = 0; i < 11; ++i) {
                tmp            = posi_num % 10;
                obj->numbuf[i] = tmp;
                posi_num -= tmp;
                posi_num /= 10;
                if (posi_num == 0) {
                        if (!is_positive)
                                obj->numbuf[i + 1] = 0xa;
                        break;
                }
        }

        for (int i = 11; i > 0; --i)
                if (obj->numbuf[i] == 0x0)
                        obj->numbuf[i] = 0xd;
                else
                        break;
}

/**
 * @brief 格式化浮点数到数字缓冲区。
 *
 * @param obj 本对象
 * @param num 浮点数
 */
static void
n_buffer_format_with_decimal (NBuffer* obj, decimal_t num)
{
        decimal_t posi_num, // num 的绝对值
                cache;
        uint32 tmp;
        uint8  grade, nflag = 11;
        bool   is_positive     = false, // 是否是正数
                use_scientific = true,  // 是否需要使用科学记数法
                is_smallnum    = false; // 是否是 -1.0 到 1.0 之间的数
        if (!obj)
                return;

        if (num >= 0)
                is_positive = true;

        posi_num = (num >= 0 ? num : -num);
        cache    = posi_num;

        if ((posi_num >= 1.0 && posi_num < 1e5) || posi_num == 0.0) {
                use_scientific = false;
                /*不使用科学记数法，直接跳到装载小数点位数*/
                goto step2_load_digit;
        }

        /*装载指数到科学记数法位 NBuffer::scibuf[4]*/
        if (posi_num < 1.0) {
                cache       = 10.0 / posi_num;
                is_smallnum = true;
        }

        for (grade = 0; cache > 10.0; ++grade)
                cache /= 10.0;

        for (int i = 0, tmp = grade; i < 4; ++i) {
                if (tmp > 0) {
                        obj->scibuf[i] = tmp % 10;
                        tmp -= tmp % 10;
                        tmp /= 10;
                        continue;
                }
                if (is_smallnum && tmp == 0) {
                        obj->scibuf[i] = 0xa;
                        tmp            = -1;
                        continue;
                }
                obj->scibuf[i] = 0xc;
                break;
        }
        if (obj->scibuf[3] != 0xc)
                obj->scibuf[3] = 0xb;

        cache = posi_num;
        for (int i = 0; i < grade; ++i)
                if (is_smallnum)
                        cache *= 10.0;
                else
                        cache /= 10.0;

/*装载小数点位数到 NBuffer::dotpot */
step2_load_digit:
        if (use_scientific) {
                if (is_positive)
                        obj->dotpot = 0x1;
                else
                        obj->dotpot = 0x2;
                goto step3_load_decimal;
        }
        for (grade = 1; cache > 10.0; ++grade)
                cache /= 10.0;
        if (!is_positive)
                grade += 1;
        obj->dotpot = grade;
        cache       = posi_num;

/*装载数字到 NBuffer::numbuf */
step3_load_decimal:
        if (!is_positive) {
                printf ("debug: is_negative, numbuf[%d] -> 0xa\n", nflag);
                obj->numbuf[nflag] = 0xa;
                nflag -= 1;
        }
        tmp = (uint32)cache;
        cache -= (decimal_t)tmp;

        for (uint32 i = 1000000; i > 0; i /= 10) {
                if (tmp < i)
                        continue;
                for (; i > 0; i /= 10) {
                        grade = (uint8)(tmp / i);
                        tmp -= i * grade;
                        obj->numbuf[nflag--] = grade;
                }
        }
        cache *= 1e9;
        tmp = (uint32)cache;

        for (uint32 i = 100000000; i > 1; i /= 10) {
                grade = (uint8)(tmp / i);
                tmp -= i * grade;
                obj->numbuf[nflag] = grade;
                if (!nflag)
                        break;
                --nflag;
        }
}

void
n_buffer_format (NBuffer* obj)
{
        n_buffer_clean (obj);

        /*判断数字类型，调用对应的格式化方法*/
        if (NUMBER (obj)->type == N_TYPE_INTEGER)
                n_buffer_format_with_integer (obj, NUMBER (obj)->number.l);
        else
                n_buffer_format_with_decimal (obj, NUMBER (obj)->number.f);
}
